package com.example.myapplication;

import android.os.Handler;
import android.os.Message;
import android.support.annotation.NonNull;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;

/**
 * 用于安卓中链式执行某个类函数的封装
 * Created by Administrator on 2017/6/17 0017.
 */

public class LinkRunning {
    private List<LinkTask> linkTasks =new ArrayList<>();
    private LinkRunning Own = this;
    private HashMap<String ,Object > map;
    public LinkRunning(){
        map = new HashMap<>();
    }

    private  Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    };

    /**
     * running all level
     * @param obj
     */
    public  void  RunningTask(final Object obj){
        linkTasks.clear();
        trackTask(obj.getClass());
        startRun(obj);
    }

    /**
     * running  level between leveldown,levelup
     * @param obj
     */
    public  void  RunningTask(final Object obj,int leveldown,int levelup){
        linkTasks.clear();
        trackTask(obj.getClass(),levelup,leveldown);
        startRun(obj);
    }

    /**
     * running  level between leveldown,levelup
     * @param obj
     */
    public  void  RunningTask(final Object obj,int[] list){
        linkTasks.clear();
        trackTask(obj.getClass(),list);
        startRun(obj);
    }

    private void startRun(final Object obj){
        new Thread(){
            @Override
            public void run() {
                super.run();
                final Thread backgroundThread = Thread.currentThread();
                try {
                    for (LinkTask task : linkTasks) {
                        final LinkTask finalTask = task;
                        if (task.thread.equals(LinkRunningTask.BACKGROUND)) {
                            task.m.invoke(obj,map);
                        } else {
                            handler.post(new Runnable() {
                                @Override
                                public void run() {
                                    try {
                                        finalTask.m.invoke(obj,map);
                                    } catch (IllegalAccessException e) {
                                        e.printStackTrace();
                                    } catch (InvocationTargetException e) {
                                        e.printStackTrace();
                                    }
                                    synchronized (backgroundThread) {
                                        backgroundThread.notify();
                                    }
                                }
                            });
                            synchronized (backgroundThread) {
                                wait();
                            }
                        }
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }.start();
    }

    public  void trackTask( Class<?> cl,int[] list) {
        for (Method m : cl.getDeclaredMethods()) {
            LinkRunningTask task = m.getAnnotation(LinkRunningTask.class);
            if (task != null) {
                System.out.println("Level:" + task.level() + "thread"
                        + task.thread());
                LinkTask linkTask = new LinkTask();
                linkTask.m = m;
                linkTask.level = task.level();
                linkTask.thread = task.thread();
                for (int item : list) {
                    if(linkTask.level == item) {
                        linkTasks.add(linkTask);
                        break;
                    }
                }
            }
        }
        Collections.sort(linkTasks,new LevelComparator());
    }

    public  void trackTask( Class<?> cl,int up,int down) {
        for (Method m : cl.getDeclaredMethods()) {
            LinkRunningTask task = m.getAnnotation(LinkRunningTask.class);
            if (task != null) {
                System.out.println("Level:" + task.level() + "thread"
                        + task.thread());
                LinkTask linkTask = new LinkTask();
                linkTask.m = m;
                linkTask.level = task.level();
                linkTask.thread = task.thread();
                if(linkTask.level>=down&&linkTask.level<=up)
                    linkTasks.add(linkTask);
            }
        }
        Collections.sort(linkTasks,new LevelComparator());
    }

    public  void trackTask( Class<?> cl) {
        for (Method m : cl.getDeclaredMethods()) {
            LinkRunningTask task = m.getAnnotation(LinkRunningTask.class);
            if (task != null) {
                System.out.println("Level:" + task.level() + "thread"
                        + task.thread());
                LinkTask linkTask = new LinkTask();
                linkTask.m = m;
                linkTask.level = task.level();
                linkTask.thread = task.thread();
                linkTasks.add(linkTask);
            }
        }
        Collections.sort(linkTasks,new LevelComparator());
    }

    private class LevelComparator implements Comparator{

        @Override
        public int compare(Object o1, Object o2) {
            LinkTask linkTask1 = (LinkTask) o1;
            LinkTask linkTask2 = (LinkTask) o2;
            return linkTask1.level-linkTask2.level;
        }
    }

    private class LinkTask implements Comparable{
        public Method m ;
        public int level ;
        public String thread;

        @Override
        public int compareTo(@NonNull Object o) {
            LinkTask linkTask = (LinkTask) o;
            return this.level-linkTask.level;
        }
    }

    /**
     * Created by Administrator on 2017/6/17 0017.
     */
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface LinkRunningTask {
        public final static String FORGROUND = "forground";
        public final static String BACKGROUND = "background";

        public int level() default 1;
        public String thread() default "forground";
    }
}
